const utils = ((Function) => {
  /**
   * @name myCall
   * @param {*} ctx
   */
  Function.prototype.myCall = function (ctx) {
    ctx = ctx ? Object(ctx) : window;
    ctx.originFn = this;
    var args = [];
    for (var i = 1; i < arguments.length; i++) {
      args.push("arguments[" + i + "]");
      // args.push(arguments[i])
    }
    var res = eval("ctx.originFn(" + args + ")");
    // var res = ctx.originFn(...args)
    delete ctx.originFn;
    return res;
  };
  /**
   * @name myApply
   * @param {*} ctx
   * @param {Array} args
   */
  Function.prototype.myApply = function (ctx, args) {
    ctx = ctx ? Object(ctx) : window;
    ctx.originFn = this;
    var arg = [];
    if (
      typeof args !== "object" &&
      typeof args !== "function" &&
      typeof args !== "undefined"
    ) {
      throw new TypeError("Uncaught SyntaxError: Illegal newline after throw");
    }
    if (!args || Object.prototype.toString.call(args) !== "[object Array]") {
      return ctx.originFn();
    }
    for (var i = 0; i < args.length; i++) {
      arg.push("args[" + i + "]");
    }
    var res = eval("ctx.originFn(" + arg + ")");
    delete ctx.originFn;
    return res;
  };
  /**
   * @name myBind
   * @param {*} ctx
   */
  Function.prototype.myBind = function (ctx) {
    if (typeof this !== "function") {
      throw new TypeError(this + "is not a function");
    }
    var originFn = this,
      args = [].slice.call(arguments, 1),
      tempFn = function () {},
      newFn = function () {
        var newArgs = [].slice.call(arguments);
        return originFn.apply(
          this instanceof newFn ? this : ctx,
          args.concat(newArgs)
        );
      };
    tempFn.prototype = this.prototype;
    newFn.prototype = new tempFn();
    return newFn;
  };
  
  /**
   * @name myNew
   */
  function myNew() {
    var constructor = [].shift.call(arguments),
      _this = {};
      _this.__proto__ = constructor.prototype
    var res = constructor.apply(_this,arguments)
    return typeof res === 'object' ? res : _this
  }


  function myInstanceof(target,type) {
      type = type.prototype;
      target = target.__proto__;
      while(true){
        if(target === null){
            return false
        }
        if(target === type){
            return true
        }
        target = target.__proto__;
      }
  }

  return {
    myNew,myInstanceof
  };
})(Function);

export default utils;
